﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Xml;
using Microsoft.SharePoint;
using Microsoft.SharePoint.WebControls;

namespace SPPlus.CustomField.JqueryScript
{
    public class JqueryScriptFieldControl : BaseFieldControl
    {

        #region Properties
        protected override string DefaultTemplateName
        {
            get
            {
                return "JqueryScriptFieldControl";
            }
        }
        public override string DisplayTemplateName
        {
            get
            {
                //Forcing the field to use the same rendering template when in display mode
                // as when in the new and edit control modes
                return "JqueryScriptFieldControl";
            }
            set
            {
                base.DisplayTemplateName = value;
            }
        }
        protected override ITemplate ControlTemplate
        {
            get
            {
                //Force the use of the rendering template in display mode 
                // in order to write the necessary controls to the display form
                // (rather than using a DisplayPattern renderpattern in the Field Type definition)
                if (ControlMode == SPControlMode.Display)
                    return DisplayTemplate;
                else
                    return base.ControlTemplate;
            }
        }
        public override object Value
        {
            get
            {
                EnsureChildControls();
                return base.Value;
            }
            set
            {
                EnsureChildControls();
                base.Value = (String)value;
            }
        }
        private XmlDocument XmlDoc;
        #endregion

        #region Create Child Controls
        protected override void CreateChildControls()
        {
            base.CreateChildControls();
        }
        #endregion

        #region Render the client-side script in the page
        /// <summary>
        /// Render the script as defined in the custom property
        /// </summary>
        /// <param name="customProperty">Cached property storing the custom script to be rendered</param>
        public void RenderScript(string customProperty)
        {
            EnsureChildControls();

            try
            {
                if (!string.IsNullOrEmpty(customProperty))
                {
                    XmlDoc = new XmlDocument();
                    XmlDoc.LoadXml(customProperty);

                    if (XmlDoc != null)
                    {
                        if (RenderScriptInCurrentControlMode())
                        {
                            ReferenceJqueryLibraryOnPage();
                            ReferenceLibrariesOnPage();
                            WriteScriptToPage();
                        }
                    }
                }
            }
            catch { }
        }
        #endregion

        #region Test whether to render the script in this type of form
        /// <summary>
        /// Check whether the script should render for the form in it's current control mode
        /// </summary>
        /// <returns>True if the script should be rendered in the form, false otherwise</returns>
        private bool RenderScriptInCurrentControlMode()
        {
            bool retVal = false;
            try
            {
                XmlNode selectedNode = XmlDoc.SelectSingleNode(string.Format("/fielddata/{0}", Constants.VISIBLEINCONTROLMODES_XMLNODENAME));
                if (selectedNode != null)
                {
                    string currentMode = Enum.GetName(typeof(SPControlMode), this.ControlMode);
                    string visibleInModes = selectedNode.InnerText;
                    if (visibleInModes.Contains(currentMode))
                        retVal = true;
                }
            }
            catch { }
            return retVal;
        }
        #endregion

        #region Add references to the specified libraries
        /// <summary>
        /// Add references to the jQuery library as stored in the config data for this field
        /// </summary>
        private void ReferenceJqueryLibraryOnPage()
        {
            string libraryUrl = GetStringFromFieldProperties(Constants.JQUERYLIBRARY_XMLNODENAME);
            if (!string.IsNullOrEmpty(libraryUrl))
                WriteStringToLiteral("litJqueryLibrary", string.Format("<script type='text/javascript' language='javascript' src='{0}'></script>", libraryUrl));
        }
        /// <summary>
        /// Add references to JavaScript libraries as stored in the config data for this field
        /// </summary>
        private void ReferenceLibrariesOnPage()
        {
            string libraries = GetStringFromFieldProperties(Constants.LIBRARIES_XMLNODENAME);
            if (!string.IsNullOrEmpty(libraries))
            {
                string[] libraryUrls = libraries.Split(new char[] { ',' });
                if (libraryUrls.Length > 0)
                {
                    StringBuilder sb = new StringBuilder();
                    foreach (string url in libraryUrls)
                    {
                        sb.Append(string.Format("<script type='text/javascript' language='javascript' src='{0}'></script>", url));
                    }
                    WriteStringToLiteral("litLibraries", sb.ToString());
                }
            }
        }
        #endregion

        #region Render the applied script
        /// <summary>
        /// Write the cached script to the control field rendered in the form
        /// </summary>
        /// <remarks>Adds a try/catch exception block around the JavaScript to prevent bad code blocking other actions on the form</remarks>
        private void WriteScriptToPage()
        {
            string script = GetStringFromFieldProperties(Constants.SCRIPT_XMLNODENAME);
            if (!string.IsNullOrEmpty(script))
            {
                StringBuilder sb = new StringBuilder();
                sb.AppendLine("$(document).ready(function() {" + Environment.NewLine);
                sb.AppendLine("try {" + Environment.NewLine);
                sb.Append(script + Environment.NewLine);
                sb.AppendLine("}" + Environment.NewLine);
                sb.AppendLine("catch(err) { }" + Environment.NewLine);
                sb.AppendLine("});" + Environment.NewLine);

                WriteStringToLiteral("litJqueryScript", sb.ToString());
            }
        }
        #endregion

        #region Get the script from the supplied XML
        /// <summary>
        /// Extract the JavaScript to render in the page from the supplied XML
        /// </summary>
        /// <param name="xmlAsString">XML containing the script</param>
        /// <returns>The script string</returns>
        private string GetStringFromFieldProperties(string nodeName)
        {
            string retValue = string.Empty;
            try
            {
                XmlNode selectedNode = XmlDoc.SelectSingleNode(string.Format("/fielddata/{0}", nodeName));
                if (selectedNode != null)
                    retValue = selectedNode.InnerText;
            }
            catch { }
            return retValue;
        }
        #endregion

        #region Write value to literal control
        private void WriteStringToLiteral(string literalId, string valueToRender)
        {
            Control ctrl = this.Controls[0].FindControl(literalId);
            if (ctrl != null)
            {
                Literal lit = (Literal)ctrl;
                lit.Text = valueToRender;
            }
        }
        #endregion

    }
}
